import java.util.Vector;

import Pattern.Pattern;
import Pattern.PatternNode;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.text.Font;
import javafx.stage.Stage;


public class MyCanvas extends Application 
{ 
	private ConMenu patternRoot;
	
	
	@Override
	public void start(Stage primaryStage) 
	{
	    primaryStage.setTitle(MyCanvas.class.getSimpleName());
	    Group root = new Group();
	    final Canvas canvas = new Canvas(300, 250);
	    GraphicsContext gc = canvas.getGraphicsContext2D();
	    drawShapes(gc);
	    
	    canvas.setOnMouseClicked(new EventHandler<MouseEvent>() {
	    	
	        @Override
	        public void handle(MouseEvent t) {
	        	double x = canvas.getWidth()/2 - 50; 
	        	double y = canvas.getHeight()/2 - 100;
	        	MakeNode(x, y, root, null, false);
	        }
	    });
 
	    root.getChildren().addAll(canvas);
	    primaryStage.setScene(new Scene(root));
	    primaryStage.getScene().setFill(Color.WHITESMOKE);
	    primaryStage.show();
	}

	
	
	/**
	 * The main() method is ignored in correctly deployed JavaFX application.
	 * main() serves only as fallback in case the application can not be
	 * launched through deployment artifacts, e.g., in IDEs with limited FX
	 * support. NetBeans ignores main().
	 *
	 * @param args the command line arguments
	 */
	public static void main(String[] args) 
	{
	    launch(args);
	}

	
	
	/*************************************************************************************************************/
	/** Title: MakeNode																				
	/** Description: Creates a new textField in the right position in the GUI and subsequently, a new pattern node 			
	/*************************************************************************************************************/
	
	private TextField MakeNode (double x , double y, Group root, ConMenu parentMenu, boolean trans)
	{
		TextField textfield = new TextField ("New Node");
    	textfield.setLayoutX(x);
    	textfield.setLayoutY(y);
    	textfield.setMaxSize(100, 50);
    	textfield.setFont(new Font(10));
    	textfield.setAlignment(Pos.CENTER);
    	
    	MenuItem m1 = new MenuItem("Add Regular Child");
	    MenuItem m2 = new MenuItem("Add Transitive Child");
    	ConMenu cm = new ConMenu();
    	cm.getItems().addAll(m1, m2);
    	textfield.setContextMenu(cm);
    	cm.setParent(textfield);
    	cm.setParentTrans(trans);
    	
    	if (null == parentMenu) 
    	{
    		patternRoot = cm;
		}
    	
    	else
    	{
    		parentMenu.addMenuChild(cm);
    	}
    	
    	m1.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) 
			{
				MakeNode(x, y + 50, root, cm, false);
				AddLine(null, root, false, cm);
			}
    		
    	});
    	
    	m2.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) 
			{
				TextField childfield = MakeNode(x, y + 50, root, cm, true);
				AddLine(childfield, root, true, cm);
			}
    		
    	});
    	
    	root.getChildren().add(textfield);
    	return textfield;
	}
	
	
	
	/*************************************************************************************************************/
	/** Title: AddLine																				
	/** Description: Creates a line between two nodes. If trans -> dashed line. If not trans -> regular line 			
	/*************************************************************************************************************/
	
	private void AddLine (TextField childfield, Group root, boolean isTrans, ConMenu cm)
	{
		root.getChildren().removeAll(cm.getAttachedLines());
		cm.getAttachedLines().clear();
		
		for (ConMenu child : cm.getMenuChildren()) 
		{
			final Line line = new Line();
			line.setStartX(cm.getParent().getLayoutX() + 50);
		    line.setStartY(cm.getParent().getLayoutY() + 25);
		    line.setEndX(child.getParent().getLayoutX() + 50);
		    line.setEndY(child.getParent().getLayoutY());
		    
		    if (true == isTrans && child.getParent().equals(childfield))
		    {
		    	line.getStrokeDashArray().addAll(25d, 10d);
		    }
		    
		    cm.addAttachedLine(line);
		    root.getChildren().add(line);
		}
	}
	
	
	
	
	/*************************************************************************************************************/
	/** Title: drawShapes																				
	/** Description:  			
	/*************************************************************************************************************/
	
	private void drawShapes(GraphicsContext gc) 
	{
	    gc.setFill(Color.WHITESMOKE);
	    gc.fillRect(gc.getCanvas().getLayoutX(), gc.getCanvas().getLayoutY(), gc.getCanvas().getWidth(), gc.getCanvas().getHeight());
	}
	
	
	
	/*************************************************************************************************************/
	/** Title: getPattern																				
	/** Description: Parses the user generated pattern and creates a Pattern object. 			
	/*************************************************************************************************************/
	
	private Pattern getPattern ()
	{
		Vector<Vector<PatternNode>> pattern = new Vector<Vector<PatternNode>> ();
		Vector<PatternNode> rootVec = new Vector<PatternNode> ();
		PatternNode root = ParseProgram.BuildPatternNode( patternRoot.getParent().getText() );
		rootVec.add( root );
		pattern.add(rootVec);
		
		pattern.add( getSubPattern(root, patternRoot) );
		
		return new Pattern (pattern);
	}
	
	
	
	/*************************************************************************************************************/
	/** Title: getSubPattern																				
	/** Description: The recursive method to help getPattern() parse the GUI pattern. 			
	/*************************************************************************************************************/
	
	private Vector<PatternNode> getSubPattern (PatternNode parent, ConMenu parentMenu)
	{
		Vector<PatternNode> childV = new Vector<PatternNode> ();
		
		for (ConMenu child : parentMenu.getMenuChildren()) 
		{
			PatternNode patternChild = ParseProgram.BuildPatternNode( child.getParent().getText() );
			patternChild.setParent(parent);
			parent.AddPatternChild(patternChild);
			patternChild.setTransChild( child.isParentTrans() );
			
			childV.add(patternChild);
			childV.addAll( getSubPattern(patternChild, child) );
		}
		
		return childV;
	}
}
